/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc. 
 *  
 * SPDX-License-Identifier: Apache-2.0.
 * 
 * @Date: 2021-09-15 19:44:56
 * @LastEditTime: 2021-10-09 10:01:18
 * @Description:  This files is for 
 * 
 * @Modify History: 
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */
#ifndef BSP_DRIVERS_F_SDIO_H
#define BSP_DRIVERS_F_SDIO_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "ft_types.h"
#include "ft_debug.h"
#include "ft_error_code.h"
#include "kernel.h"

enum
{
    FSDIO_GENERAL_INTR = 0,
    FSDIO_IDMA_INTR,

    FSDIO_MAX_INTR_TYPE
};

enum
{
    FSDIO_BUS_WIDTH_1 = 1, /* 2^0 = 1 */
    FSDIO_BUS_WIDTH_4 = 4, /* 2^2 = 4*/
    FSDIO_BUS_WIDTH_8 = 8  /* 2^3 = 8*/
};

typedef struct
{
    u32 attribute; /* ds0描述符 */
#define FSDIO_IDMAC_DES0_DIC	BIT(1)//内部描述表不触发TI/RI中断
#define FSDIO_IDMAC_DES0_LD	    BIT(2)//数据的最后一个描述符
#define FSDIO_IDMAC_DES0_FD	    BIT(3)//数据的第一个描述符
#define FSDIO_IDMAC_DES0_CH	    BIT(4)//链接下一个描述符地址
#define FSDIO_IDMAC_DES0_ER	    BIT(5)//last des
#define FSDIO_IDMAC_DES0_CES	BIT(30)//RINTSTS寄存器错误汇总
#define FSDIO_IDMAC_DES0_OWN	BIT(31)//描述符关联DMA，完成传输后该位置置0
    u32 non1; /* ds1描述符域不使用 */
    u32 len; /* ds2描述符域 bit[25:13] buffer2 大小，bit[12:0] buffer1 大小*/
#define FSDIO_IDMAC_DES2_BUF1_MASK      GENMASK(12, 0)
#define FSDIO_IDMAC_DES2_BUF1_SIZE(x)  (FSDIO_IDMAC_DES2_BUF1_MASK & (x))
#define FSDIO_IDMAC_DES2_BUF2_MASK      GENMASK(25, 13)
#define FSDIO_IDMAC_DES2_BUF2_SIZE(x)  (FSDIO_IDMAC_DES2_BUF2_MASK & (x << 13))
    u32 non2; /* ds3描述符域不使用 */
    u32 addr_lo; /* ds4 Lower 32-bits of Buffer Address Pointer 1 --> buffer 1 */
    u32 addr_hi; /* ds5 Upper 32-bits of Buffer Address Pointer 1*/
    u32 desc_lo; /* ds6 Lower 32-bits of Next Descriptor Address --> buffer 2 */
    u32 desc_hi; /* ds7 Upper 32-bits of Next Descriptor Address */
} __packed __aligned(4) FSdioIdmaDesc; /* ADMA descriptor. Each descriptor can transfer up to 4KB of data in chained mode */

typedef struct
{
    FSdioIdmaDesc *idma_desc;       /* IDMA descriptor table, pointer to FSdioIdmaDesc array */
    uintptr        idma_addr;       /* Mapped IDMA descr. table, the physical address of adma_table array */
    u32            idma_desc_sz;    /* IDMA descriptor size */
} FSdioIdmaTbl;

typedef struct
{
    u32 instance_id;    /**< Unique ID  of sdio ctrl instance */ 
    u32 base_addr;      /**< Base address of the device */
    u32 irq_num;        /**< Interrupt num */ 
    u32 irq_priority;   /**< Interrupt priority */
    boolean enable_irq; /**< Interrupt on/off ctrl when init */
    const char *irq_name; /**< Interrupt name */
} FSdioConfig;

typedef void (*FSdioIntrHandler)(s32 vector, void *ctrl_p);

typedef struct
{
    FSdioConfig config;
    u32 is_ready; /**< Device is initialized and ready */
    u32 version;  /**< Host controller version */
    FSdioIntrHandler intr_handler; /**< Intrrupt handler */
    FSdioIdmaTbl idma_tbl; /**< DMA channel */
} FSdioCtrl;

/**
 * @name: FSdioSetCardClk
 * @msg: 设置SDIO卡参考时钟频率
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 * @param {u32} input_clk_hz
 */
u32 FSdioSetCardClk(FSdioCtrl *ctrl_p, u32 input_clk_hz);
/**
 * @name: FSdioInitialize
 * @msg: 初始化SDIO控制器
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 * @param {FSdioConfig} *config_p
 */
u32 FSdioInitialize(FSdioCtrl *ctrl_p, const FSdioConfig *config_p);
/**
 * @name: FSdioDeInitialize 
 * @msg: 去初始化SDIO控制器
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 */
void FSdioDeInitialize(FSdioCtrl *ctrl_p);
/**
 * @name: FSdioCtrlReset
 * @msg: 重置SDIO控制器
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 * @param {u32} reset_bits
 */
u32 FSdioCtrlReset(FSdioCtrl *ctrl_p, u32 reset_bits);
/**
 * @name: FSdioLookupConfig
 * @msg: 获取SDIO控制器默认配置
 * @return {*}
 * @param {u32} instance_id
 */
const FSdioConfig *FSdioLookupConfig(u32 instance_id);
/**
 * @name: FSdioGetIntrMask
 * @msg: 获取SDIO控制器中断掩码
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 * @param {u32} intr_type
 */
u32 FSdioGetIntrMask(FSdioCtrl *ctrl_p, u32 intr_type);
/**
 * @name: FSdioSetIntrMask
 * @msg: 设置SDIO控制器中断掩码
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 * @param {u32} intr_type
 * @param {u32} set_mask
 * @param {boolean} enable
 */
void FSdioSetIntrMask(FSdioCtrl *ctrl_p, u32 intr_type, u32 set_mask, boolean enable);
/**
 * @name: FSdioSetBusWidth
 * @msg: 设置SDIO总线位宽
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 * @param {u32} width
 */
void FSdioSetBusWidth(FSdioCtrl *ctrl_p, u32 width);
/**
 * @name: FSdioGetBusWidth
 * @msg: 获取当前SDIO总线位宽
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 */
u32 FSdioGetBusWidth(FSdioCtrl *ctrl_p);
/**
 * @name: FSdioSetDdrMode
 * @msg: 设置SDIO卡的DDR模式
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 * @param {boolean} enable
 */
void FSdioSetDdrMode(FSdioCtrl *ctrl_p, boolean enable);
/**
 * @name: FSdioCardExists
 * @msg: 检测SDIO卡是否在位
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 */
boolean FSdioCardExists(FSdioCtrl *ctrl_p);
/**
 * @name: FSdioCardWriteProtected
 * @msg: 检测SDIO卡是否写保护
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 */
boolean FSdioCardWriteProtected(FSdioCtrl *ctrl_p);
/**
 * @name: FSdioSendPrivateCmd
 * @msg: 发送SDIO命令
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 * @param {u32} cmd
 * @param {u32} arg
 */
u32 FSdioSendPrivateCmd(FSdioCtrl *ctrl_p, u32 cmd, u32 arg);
/**
 * @name: FSdioIDmaTblInit
 * @msg: 初始化SDIO DMA描述符表
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 * @param {FSdioIdmaTbl} *idma_tbl
 */
u32 FSdioIDmaTblInit(FSdioCtrl *ctrl_p, FSdioIdmaTbl *idma_tbl);
/**
 * @name: FSdioWriteIdmaDesc
 * @msg: 写SDIO DMA描述符
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 * @param {FSdioIdmaDesc} *desc_p
 * @param {uintptr} addr
 * @param {u32} len
 * @param {u32} attribute
 */
void FSdioWriteIdmaDesc(FSdioCtrl *ctrl_p, FSdioIdmaDesc *desc_p, uintptr addr, u32 len, u32 attribute);
/**
 * @name: FSdioStopIdma
 * @msg: 停止SDIO DMA传输
 * @return {*}
 * @param {FSdioCtrl} *ctrl_p
 */
void FSdioStopIdma(FSdioCtrl *ctrl_p);

#define FSDIO_SUCCESS FT_SUCCESS
#define FSDIO_ERR_TIMEOUT       FT_MAKE_ERRCODE(ErrModBsp, ErrBspMmc, BIT(0)) /* 处理超时 */
#define FSDIO_ERR_NOT_READY     FT_MAKE_ERRCODE(ErrModBsp, ErrBspMmc, BIT(1)) /* 控制器未初始化 */
#define FSDIO_ERR_BUS_BUSY      FT_MAKE_ERRCODE(ErrModBsp, ErrBspMmc, BIT(2)) /* 总线繁忙无法响应 */
#define FSDIO_ERR_CMD_FAILED    FT_MAKE_ERRCODE(ErrModBsp, ErrBspMmc, BIT(3)) /* CMD处理失败 */
#define FSDIO_ERR_INVALID_PARA  FT_MAKE_ERRCODE(ErrModBsp, ErrBspMmc, BIT(4)) /* 输入参数非法 */
#define FSDIO_ERR_CARD_NO_FOUND FT_MAKE_ERRCODE(ErrModBsp, ErrBspMmc, BIT(5)) /* 卡不在位 */

#define FSDIO_DEBUG_TAG "FSDIO"
#define FSDIO_ERROR(format, ...)   FT_DEBUG_PRINT_E(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDIO_INFO(format, ...)    FT_DEBUG_PRINT_I(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)
#define FSDIO_DEBUG(format, ...)   FT_DEBUG_PRINT_D(FSDIO_DEBUG_TAG, format, ##__VA_ARGS__)

#define FSDIO_DEF_BLK_SIZE			512     /* sd/mmc block size */
#define FSDIO_TIMEOUT              (500)  /* timeout for retries */
#define FSDIO_DELAY_US             (5)
#define FSDIO_400_KHZ              (400000UL)
#define FSDIO_25_MHZ               (25000000UL)

#ifdef __cplusplus
}
#endif

#endif